package com.ncmmall.application.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import com.feijin.commons.lang.PropertiesHelps;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConfig;
import com.github.wxpay.sdk.WXPayUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付
 *
 * @author likaikai
 * @date 2021-1-5 13:54:38
 */
@Slf4j
public class WechatPayUtil {

    private static final WXPayConfig WX_PAY_CONFIG = new WXPayConfig() {

        @Override
        public String getAppID() {
            return PropertiesHelps.getValue("app.wx.appid");
        }

        @Override
        public String getMchID() {
            return PropertiesHelps.getValue("app.wx.mch_id");
        }

        @Override
        public String getKey() {
            return PropertiesHelps.getValue("app.wx.key");
        }

        @Override
        public InputStream getCertStream() {
            try {
                return new FileInputStream(PropertiesHelps.getValue("app.wx.refund.path"));
            } catch (FileNotFoundException e) {
                return null;
            }
        }

        @Override
        public int getHttpConnectTimeoutMs() {
            return 10000;
        }

        @Override
        public int getHttpReadTimeoutMs() {
            return 10000;
        }

    };

    private static final WXPay WX_PAY = new WXPay(WX_PAY_CONFIG);
    private static final String IP = PropertiesHelps.getValue("wx.spbill_create_ip");

    /**
     * 创建app支付订单
     *
     * @param body       订单描述
     * @param outTradeNo 订单编号
     * @param totalFee   订单金额,单位元
     * @param notifyUrl  回调地址
     * @return app调起参数
     */
    public static Map<String, String> createAppOrder(String body, String outTradeNo, double totalFee, String notifyUrl)
            throws Exception {

        Map<String, String> reqData = new HashMap<>();

        reqData.put("body", body);
        reqData.put("out_trade_no", outTradeNo);
        reqData.put("total_fee", String.valueOf((int) NumberUtil.mul(totalFee, 100)));
        reqData.put("spbill_create_ip", IP);
        reqData.put("notify_url", notifyUrl);
        reqData.put("trade_type", "APP");
        Map<String, String> response = WX_PAY.unifiedOrder(reqData);

        log.info("微信统一下单响应: {}", response);

        if (!"success".equalsIgnoreCase(response.get("return_code"))) {
            throw new IllegalArgumentException(response.get("return_msg"));
        }

        Map<String, String> result = new HashMap<>();
        result.put("appid", WX_PAY_CONFIG.getAppID());
        result.put("partnerid", WX_PAY_CONFIG.getMchID());
        result.put("prepayid", MapUtil.getStr(response, "prepay_id"));
        result.put("package", "Sign=WXPay");
        result.put("noncestr", WXPayUtil.generateNonceStr());
        result.put("timestamp", String.valueOf(DateUtil.currentSeconds()));
        result.put("sign", WXPayUtil.generateSignature(result, WX_PAY_CONFIG.getKey()));
        return result;

    }

//    /**
//     * 创建PC支付订单
//     *
//     * @param subject     订单描述
//     * @param outTradeNo  订单编号
//     * @param totalAmount 订单金额，字符串，单位元，精确到小数2位
//     * @param notifyUrl   回调地址
//     * @return 支付字符串
//     * @throws Exception 创建订单异常
//     */
//    public String createPageOrder(String subject, String outTradeNo, String totalAmount, String notifyUrl)
//            throws Exception {
//        return Factory.Payment.Page().asyncNotify(notifyUrl).pay(subject, outTradeNo, totalAmount, "").getBody();
//    }

//    /**
//     * 创建PC二维码支付订单
//     *
//     * @param subject     订单描述
//     * @param outTradeNo  订单编号
//     * @param totalAmount 订单金额，字符串，单位元，精确到小数2位
//     * @param notifyUrl   回调地址
//     * @return 支付二维码链接
//     * @throws Exception 创建订单异常
//     */
//    public String createPageCodeOrder(String subject, String outTradeNo, String totalAmount, String notifyUrl)
//            throws Exception {
//        return Factory.Payment.FaceToFace().asyncNotify(notifyUrl).preCreate(subject, outTradeNo, totalAmount).getQrCode();
//    }

//    /**
//     * 创建手机浏览器支付订单
//     *
//     * @param subject     订单描述
//     * @param outTradeNo  订单编号
//     * @param totalAmount 订单金额，字符串，单位元，精确到小数2位
//     * @param notifyUrl   回调地址
//     * @return 支付字符串
//     * @throws Exception 创建订单异常
//     */
//    public String createWapOrder(String subject, String outTradeNo, String totalAmount, String notifyUrl)
//            throws Exception {
//        return Factory.Payment.Wap().asyncNotify(notifyUrl).pay(subject, outTradeNo, totalAmount, "", "").getBody();
//    }

    /**
     * 订单申请退款
     *
     * @param outTradeNo  订单编号
     * @param outRefundNo 退款编号
     * @param refundFee   退款金额
     */
    public static Map<String, String> refund(String outTradeNo, String outRefundNo, double totalFee, double refundFee) {

        Map<String, String> data = new HashMap<>();
        try {
            Map<String, String> reqData = new HashMap<>();
            reqData.put("out_trade_no", outTradeNo);
            reqData.put("out_refund_no", outRefundNo);
            reqData.put("total_fee", String.valueOf((int) (totalFee * 100)));
            reqData.put("refund_fee", String.valueOf((int) (refundFee * 100)));

            Map<String, String> map = WX_PAY.refund(reqData);
            log.info("退款返回：" + map);

            if ("FAIL".equals(map.get("result_code"))) {
                log.error("[微信退款请求失败,错误原因]" + map.get("err_code_des"));
                data.put("flag", "false");
                data.put("message", map.get("err_code_des"));
                return data;
            }

            if ("SUCCESS".equals(map.get("return_code")) && "SUCCESS".equals(map.get("result_code"))) {
                log.info("退款请求成功");
                data.put("flag", "true");
                data.put("no", map.get("refund_id"));
            } else {
                log.error("[微信退款提交业务失败,错误原因]" + map.get("err_code_des"));
                data.put("flag", "false");
                data.put("message", map.get("err_code_des"));
            }
        } catch (Exception e) {
            log.error("[退款异常]", e);
            data.put("flag", "false");
        }
        return data;
    }

    /**
     * 查询订单支付状态
     *
     * @param outTradeNo 订单编号
     * @throws Exception 查询异常
     */
    public static boolean tradeQuery(String outTradeNo) throws Exception {
        Map<String, String> reqData = new HashMap<>();
        reqData.put("out_trade_no", outTradeNo);
        Map<String, String> response = WX_PAY.orderQuery(reqData);
        return "SUCCESS".equals(MapUtil.getStr(response, "trade_state"));
    }

    /**
     * 异步通知校验
     *
     * @param reqData 响应参数
     * @throws Exception 校验异常
     */
    public static boolean verifyNotify(Map<String, String> reqData) throws Exception {
        return WX_PAY.isPayResultNotifySignatureValid(reqData);
    }

}
